package com.zhang.hadoop.spring.service;

import com.alibaba.fastjson.JSONObject;
import com.zhang.hadoop.spring.annotation.ActionAnnotation;
import com.zhang.hadoop.spring.bean.Action;
import com.zhang.hadoop.spring.bean.ActionResult;
import com.zhang.hadoop.spring.facotry.WorkerFactory;
import jdk.internal.util.xml.impl.ReaderUTF8;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * @author zhang yufei
 * @date 2022/4/14 10:39 上午
 **/
@Service
public class ActionService {

    private static final List<Class> WRAP_CLASS = Arrays.asList(Integer.class, Boolean.class, Double.class,Byte.class,Short.class, Long.class, Float.class, Double.class, BigDecimal.class, String.class);

    @Qualifier("taskExecutor")
    private ThreadPoolTaskExecutor taskExecutor;

    @Resource
    private WorkerFactory workerFactory;

    @Resource
    private MockTest mockTest;

    public void startAction() {
        Map<String, Object> workerMap = workerFactory.getWorkerMap();
        for (Map.Entry<String, Object> worker : workerMap.entrySet()) {
            Method[] methods = worker.getValue().getClass().getMethods();
            for (Method method : methods) {
                if (method.isAnnotationPresent(ActionAnnotation.class)) {
                    while(true){
                        try {
                            String actionDefName = AnnotationUtils.getAnnotation(method, ActionAnnotation.class).actionDefName();
                            Action action = getAction(actionDefName);
                            String inputData = action.getInputData();
                            int parameterCount = method.getParameterCount();
                            ActionResult actionResult = generateActionResult(action);
                            if (parameterCount == 0) {

                            } else if (parameterCount == 1) {
                                Object data = parseDataSingle(inputData, method.getParameters()[0]);
                                Object result = method.invoke(worker.getValue(), data);
                                actionResult.setOutputData(JSONObject.toJSONString(result));
                            } else {
                                List<Object> paramList = parseDataMulti(inputData, method);
                                Object result = method.invoke(worker.getValue(), paramList.toArray());
                                actionResult.setOutputData(JSONObject.toJSONString(result));
                            }
                            sendResult(actionResult);
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }

                }
            }
        }
    }

    public Action getAction(String actionDefName) {
        Action action = mockTest.getData(actionDefName);
        return action;
    }

    public ActionResult generateActionResult(Action action) {
        ActionResult actionResult = new ActionResult();
        actionResult.setWorkflowInstanceId(action.getWorkflowId());
        actionResult.setActionId(action.getActionId());
        return actionResult;
    }

    public void sendResult(ActionResult actionResult) {
        mockTest.sendResult(actionResult);
    }

    public Object parseDataSingle(String data, Parameter parameter) {
        if (parameter.getType().isPrimitive()) {

        } else if (parameter.getType() == String.class) {
            return data;
        } else {
            return JSONObject.parseObject(data, parameter.getType());
        }
        return null;
    }

    public List<Object> parseDataMulti(String data, Method method) {
        LocalVariableTableParameterNameDiscoverer local = new LocalVariableTableParameterNameDiscoverer();
        String[] parameterNames = local.getParameterNames(method);
        List<Object> result = new ArrayList<>(method.getParameters().length);
        JSONObject jsonObject = JSONObject.parseObject(data);
        for (int i = 0; i < method.getParameters().length; i++) {
            Parameter parameter = method.getParameters()[i];
            if (parameter.getType().isPrimitive()) {
                result.add(jsonObject.get(parameterNames[i]));
            } else if (parameter.getType() == Integer.class) {
                result.add(jsonObject.get(parameterNames[i]));
            } else if (parameter.getType() == Long.class) {
                result.add(jsonObject.get(parameterNames[i]));
            } else if (parameter.getType() == String.class) {
                result.add(jsonObject.get(parameterNames[i]));
            } else {
                result.add(JSONObject.parseObject(jsonObject.getString(data), parameter.getType()));
            }
        }
        return result;
    }
}
